﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 *
 *  This code is provided on an AS IS basis, with no WARRANTIES,
 *  CONDITIONS or GUARANTEES of any kind.
 *
 **/

using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel.Composition;
using System.Windows.Input;
using System.Xml.Serialization;
using Peter.Common;
using Peter.Common.Interfaces;
using Peter.Common.MainMenu;
using Peter.Common.Services;
using Peter.Common.Utilities;
using Peter.Properties;

namespace Peter.Data
{
   /// <summary>
   /// General options for peter.
   /// </summary>
   [Export (typeof (IOptionPage))]
   [PartCreationPolicy (CreationPolicy.Shared)]
   public class OptionsGeneral : ViewModelBase, IOptionPage, IPartImportsSatisfiedNotification
   {
      private string m_SelectedTheme;
      private string m_SelectedOpenItem;
      private RelayCommand m_AddOpenDocCommand;
      private RelayCommand m_RemoveOpenDocCommand;
      private readonly Collection<string> m_SearchHistory;
      private readonly Collection<string> m_CommandHistory;
      private readonly ObservableCollection<string> m_Themes;
      private readonly ObservableCollection<string> m_StartupFiles;
      private readonly ObservableCollection<string> m_RecentFileList;

      /// <summary>
      /// Initializes a new general options object.
      /// </summary>
      public OptionsGeneral ()
      {
         this.SelectedTheme = "Default";
         this.m_SearchHistory = new Collection<string> ();
         this.m_CommandHistory = new Collection<string> ();
         this.m_Themes = new ObservableCollection <string>
         {
            "Light",
            "Dark"
         };
         this.m_StartupFiles = new ObservableCollection<string> ();
         this.m_RecentFileList = new ObservableCollection<string> ();
         foreach (var startupFile in Settings.Default.StartupFiles)
            this.StartupFiles.Add (startupFile);
         this.m_StartupFiles.CollectionChanged += this.OnStartupFilesChanged;
      }

      /// <summary>
      /// Gets the name of the option page.
      /// </summary>
      public string Name
      {
         get { return "General"; }
      }

      /// <summary>
      /// Gets the icon of the option page.
      /// </summary>
      public MainMenuIcon OptionPageIcon
      {
         get { return MainMenuIcon.Cog; }
      }

      /// <summary>
      /// Gets the peter data.
      /// </summary>
      [XmlIgnore]
      [Import (typeof (IPeterData))]
      public IPeterData PeterData { get; set; }

      /// <summary>
      /// Gets or Sets the selected open item.
      /// </summary>
      [XmlIgnore]
      public string SelectedOpenItem
      {
         get { return this.m_SelectedOpenItem; }
         set
         {
            this.m_SelectedOpenItem = value;
            this.OnPropertyChanged ("SelectedOpenItem");
         }
      }

      /// <summary>
      /// Gets or Sets the selected theme.
      /// </summary>
      public string SelectedTheme
      {
         get { return this.m_SelectedTheme; }
         set
         {
            this.m_SelectedTheme = value;
            this.OnPropertyChanged ("SelectedTheme");
            this.OnThemeChanged ();
         }
      }

      /// <summary>
      /// Get the search history.
      /// </summary>
      public Collection<string> SearchHistory { get { return this.m_SearchHistory; } }

      /// <summary>
      /// Get the command history.
      /// </summary>
      public Collection<string> CommandHistory { get { return this.m_CommandHistory; } }

      /// <summary>
      /// Gets the collection of themes.
      /// </summary>
      [XmlIgnore]
      public ObservableCollection<string> Themes { get { return this.m_Themes; } }

         /// <summary>
      /// Get the list of startup files.
      /// </summary>
      [XmlIgnore]
      public ObservableCollection<string> StartupFiles { get { return this.m_StartupFiles; } }

      /// <summary>
      /// Get the list of recently opened files.
      /// </summary>
      public ObservableCollection<string> RecentFileList { get { return this.m_RecentFileList; } }

      /// <summary>
      /// Occurs when the theme is changed.
      /// </summary>
      private void OnThemeChanged ()
      {
         
      }

      /// <summary>
      /// Gets the add open document command.
      /// </summary>
      [XmlIgnore]
      public ICommand AddOpenDocCommand
      {
         get { return this.m_AddOpenDocCommand ?? (this.m_AddOpenDocCommand = new RelayCommand (this.OnAddOpenDoc, CanAddOpenDoc)); }
      }

      /// <summary>
      /// Gets the remove open document command.
      /// </summary>
      [XmlIgnore]
      public ICommand RemoveOpenDocCommand
      {
         get { return this.m_RemoveOpenDocCommand ?? (this.m_RemoveOpenDocCommand = new RelayCommand (this.OnRemoveOpenDoc, this.CanRemoveOpenDoc)); }
      }

      /// <summary>
      /// Checks to see if the remove open document command can execute.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      /// <returns>True if command can execute, otherwise false.</returns>
      private bool CanRemoveOpenDoc (object obj)
      {
         return Settings.Default.StartupSpecificDocs && this.SelectedOpenItem != null;
      }

      /// <summary>
      /// Executes the remove open document command.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void OnRemoveOpenDoc (object obj)
      {
         if (this.StartupFiles.Contains (this.SelectedOpenItem))
            this.StartupFiles.Remove (this.SelectedOpenItem);
      }

      /// <summary>
      /// Checks to see if the add open document command can execute.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      /// <returns>True if command can execute, otherwise false.</returns>
      private static bool CanAddOpenDoc (object obj)
      {
         return Settings.Default.StartupSpecificDocs;
      }

      /// <summary>
      /// Occurs when the startup file list changes.
      /// </summary>
      /// <param name="sender">Startup file list.</param>
      /// <param name="e">NotifyCollectionChangedEventArgs</param>
      private void OnStartupFilesChanged (object sender, NotifyCollectionChangedEventArgs e)
      {
         Settings.Default.StartupFiles.Clear ();
         foreach (var startupFile in this.m_StartupFiles)
            Settings.Default.StartupFiles.Add (startupFile);
      }

      /// <summary>
      /// Executes the add open document command.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void OnAddOpenDoc (object obj)
      {
         var ofd = ServiceManager.Get <IOpenFileService> ();
         ofd.AllowMultipleSelection = true;
         ofd.Title = "Select documents to open on startup";
         if (ofd.ShowDialog ())
         {
            foreach (var fileName in ofd.FileNames)
            {
               if (!this.StartupFiles.Contains (fileName))
                  this.StartupFiles.Add (fileName);
               else
                  Console.WriteLine (Resources.AlreadyInOpenFiles, fileName);
            }
         }
      }

      /// <summary>
      /// Loads the data from xml.
      /// </summary>
      /// <param name="xmlToLoad">Xml string to load.</param>
      public void LoadFromXml (string xmlToLoad)
      {
         try
         {
            var loadedData = Serialization.DeserializeFromString<OptionsGeneral> (xmlToLoad);
            this.CopyPropertiesFrom (loadedData);
         }
         catch (Exception ex)
         {
            Console.Error.WriteLine (ex.Message);
         }
      }

      /// <summary>
      /// Saves any data to xml.
      /// </summary>
      /// <returns>The data to save in Xml format.</returns>
      public string SaveToXml ()
      {
         return this.Serialize ();
      }

      /// <summary>Called when a part's imports have been satisfied and it is safe to use.</summary>
      public void OnImportsSatisfied ()
      {
         var type = this.GetType ().ToString ();
         this.LoadFromXml (this.PeterData.RequestData (type));
      }
   }
}
